package com.odontosis.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.odontosis.entidade.Recibo;
import com.odontosis.entidade.ReciboDetalhe;
import com.odontosis.entidade.TipoServico;
import com.odontosis.ioc.ContainerIoc;

/**
 * 
 * @author pablo
 * 
 */
public class ImpressaoPortaParalela {

	private static final String ARQUIVO_BAT = ContainerIoc.getParametrosService().buscarEndereecoBatImpressao();
	protected static final Log LOG = LogFactory.getLog(ImpressaoPortaParalela.class);

	/**
	 * Endereco de rede ou porta onde a impressora a ser utilizada está
	 * instalada
	 */
	private String enderecoImpressora;

	/**
	 * Texto que será impresso, é um vetor de Strings onde cada posição do vetor
	 * indica uma linha a ser impressa
	 */
	private List<String> texto;
	
	/**
	 * Define o tipo da impressão o default está parametrizado na base de dados
	 */
	private int tipoImpressao;
	
	

	public List<String> montarReciboComCPF(String cpf, String usuario,
			String emitente, String endereco, Recibo recibo) {
		inserirCabecalho(recibo);
		inserirDetalhe(recibo);
		texto.add("CPF: " + cpf);
		inserirRodape(emitente, endereco, usuario, recibo);
		if(LOG.isDebugEnabled()) {
			for(String a : texto) {
				LOG.debug(a);
			}
		}
		return texto;
	}

	public List<String> montarReciboSemCPF(String usuario, String emitente,
			String endereco, Recibo recibo) {
		inserirCabecalho(recibo);
		inserirDetalhe(recibo);
		inserirRodape(emitente, endereco, usuario, recibo);
		if(LOG.isDebugEnabled()) {
			for(String a : texto) {
				LOG.debug(a);
			}
		}
		return texto;
	}

	public List<String> montarReciboComCNPJ(String cnpj, String usuario,
			String emitente, String endereco, Recibo recibo) {
		inserirCabecalho(recibo);
		inserirDetalhe(recibo);
		texto.add("CNPJ: " + cnpj);		
		inserirRodape(emitente, endereco, usuario, recibo);
		if(LOG.isDebugEnabled()) {
			for(String a : texto) {
				LOG.debug(a);
			}
		}
		return texto;
	}

	private void inserirDetalhe(Recibo recibo) {
		try {
			ContainerIoc.getReciboService().refresh(recibo);
		}catch (Exception e) {
			//System.err.println(e.printStackTrace());
			//TODO: não lançar excpetion
			//throw new RuntimeException("Falha ao montar o detalhe de impressão do recibo. ");
		}
		if(recibo.getListaReciboDetalhe() != null && !recibo.getListaReciboDetalhe().isEmpty()) {
			texto.add("Detalhes");
			for(ReciboDetalhe reciboDetalhe : recibo.getListaReciboDetalhe()) {
				texto.add(" - Vencimento: " + reciboDetalhe.getPagamento().getMesVencimento() + "/" + reciboDetalhe.getPagamento().getAnoVencimento() + " Parcela: " + reciboDetalhe.getPagamento().getNumeroParcela() + " Valor: " +StringUtilsOdontosis.formatarDouble(reciboDetalhe.getValor().doubleValue()));
			}
		}
		
	}
	/**
	 * Imprime o recibo
	 * 
	 * @throws Exception
	 */
	public void imprimir() throws Exception {
		tipoImpressao = ContainerIoc.getParametrosService().buscarTipoImpressao();
		if(tipoImpressao == 1) {
			imprimirComBat1();
			Runtime.getRuntime().exec("cmd /c " + ARQUIVO_BAT);
		} else if(tipoImpressao == 2) {
			for(int i = 0; i < 10; i++) {
				texto.add(".");
			}
			imprimirComBat2();
			Runtime.getRuntime().exec("cmd /c " + ARQUIVO_BAT);
		} else if(tipoImpressao == 3) {
		
			for (String linha : texto) {
				String executar = "cmd /c echo " + linha + " > "
						+ getEnderecoImpressora();
				if (linha.equals(".")) {
					executar = "cmd /c echo. " + " > " + getEnderecoImpressora();
				}
				Runtime.getRuntime().exec(executar);
				// delay para imprimir os dados na ordem correta de impresão
				// utilizado
				Thread.sleep(300);
			}
			// da espaços para cortar o papel
			for (int i = 0; i < 10; i++) {
				Runtime.getRuntime().exec(
						"cmd /c echo." + " > " + getEnderecoImpressora());
			}
		} else if(tipoImpressao == 4) {
			
			imprimirDiretoEndereco();
			
		}
	}

	public void imprimirComBat1() {
		PrintWriter pw = null;
		try {
			pw = new PrintWriter(new FileOutputStream(ARQUIVO_BAT));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		pw.append("@echo off");
		for (String linha : texto) {
			String executar = "echo " + linha + " > " + getEnderecoImpressora();
			if (linha.equals(".")) {
				executar = "echo. " + " > " + getEnderecoImpressora();
			}
			pw.append("\n" +executar);
		}
		

		pw.flush();
		pw.close();
		
	}
	
	public void imprimirComBat2() {
		PrintWriter pw = null;
		try {
			pw = new PrintWriter(new FileOutputStream(ARQUIVO_BAT));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		int cont = 0;
		
		pw.append("@echo off");
		for (String linha : texto) {
			String executar = "echo " + linha + " > "
					+ getEnderecoImpressora();
			if (linha.equals(".")) {
				executar = "echo. " + " > " + getEnderecoImpressora();
			}
			pw.append("\n" + executar);
			
			    
				pw.append("\n"+ "set loop=1");
				pw.append("\n"+ ":back" + cont);
				pw.append("\n"+ "if \"%loop%\"==\"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" goto end" + cont);
				pw.append("\n"+ "set loop=%loop%1");
				pw.append("\n"+ "goto back" + cont);
				pw.append("\n"+ ":end" + cont);
				
				cont++;
			
		}

		pw.flush();
		pw.close();
		
	}
	
	public void imprimirDiretoEndereco() {
		StringBuffer impressao = new StringBuffer();
		try {
			File f = new File(getEnderecoImpressora());

			RandomAccessFile raf = new RandomAccessFile(f, "rw");
			
			for (String linha : texto) {
				if (linha.equals(".")) {
					impressao.append("\n");
				} else  {
					impressao.append("\n" + linha);
				}
			}
			
			raf.writeBytes(impressao.toString());
			raf.close();

		} catch (IOException e) {
			throw new RuntimeException("Falha na Impressão");
		} 
	}
	

	private String centralizarComCerquilha(String frase) {
		int tamanho = frase.length();
		int nCerquilhas = 47 - tamanho;
		String retorno = "";
		for (int i = 0; i < nCerquilhas / 2; i++) {
			retorno += "#";
		}
		retorno += frase;
		for (int i = 0; i < nCerquilhas / 2; i++) {
			retorno += "#";
		}
		return retorno;
	}

	private void inserirCabecalho(Recibo recibo) {
		texto = new ArrayList<String>();
		SimpleDateFormat formato = new SimpleDateFormat("dd/MM/yyyy HH:mm");
		String dataFormatada = formato.format(new Date());
		texto.add("Via: " + recibo.getVersao());
		texto.add(dataFormatada);
		texto.add("Número: " + StringUtilsOdontosis.colocaZeros(recibo.getId().toString(), 10));
		// 46 # total de colunas na linha de impressão
		texto.add("##############################################");
		texto.add(centralizarComCerquilha("RECIBO"));
		texto.add("##############################################");
		if (recibo.getPagamento().getServico().getTipoServico() == TipoServico.MANUTENCAO) {
			texto.add("Parcela: " + recibo.getNumeroParcela());
		} else {
			texto.add("Parcela: " + recibo.getNumeroParcela() + "/"
					+ recibo.getTotalParcelas());
		}
		texto.add("Vencimento: " + recibo.getPagamento().getMesVencimento()
				+ "/" + recibo.getPagamento().getAnoVencimento());
		texto.add(".");
		texto.add("Recebi de "
				+ recibo.getPagamento().getServico().getPacienteServico()
						.getNome());
		texto.add("O valor de R$"
				+ StringUtilsOdontosis.formatarDouble(recibo.getValor()
						.doubleValue()));
		if (recibo.getPagamento().getServico().getTipoServico() == TipoServico.MANUTENCAO) {
			texto.add("Referente à mensalidade de  "
					+ recibo.getPagamento().getServico().getTipoServico()
							.getDescricao());
		} else if (recibo.getPagamento().getServico().getTipoServico() == TipoServico.OUTROS_ACRESCIMOS) {
			texto.add("Referente a meus serviços profissionais");
		} else {
			texto.add("Referente ao serviço de "
					+ recibo.getPagamento().getServico().getTipoServico()
							.getDescricao());
		}
	}

	private void inserirRodape(String emitente, String endereco,
			String usuario, Recibo recibo) {
		texto.add(emitente);
		texto.add("Ortodontista, Mestre ATM e Dor Facial");
		texto.add(endereco);
		if (recibo.getReciboAnulado() != null) {
			texto.add("Este recibo anula o recibo de número "
					+ StringUtilsOdontosis.colocaZeros(recibo
							.getReciboAnulado().getId().toString(), 10));
		}
		texto.add(".");
		texto.add(".");
		texto.add("______________________________________________");
		texto.add(usuario);
	}

	// ****************Getters and Setters************/
	public String getEnderecoImpressora() {
		if(enderecoImpressora == null) {
			throw new RuntimeException("O Endereço da impressora está vazio");
		}
		return enderecoImpressora;
	}

	public List<String> getTexto() {
		return texto;
	}

	public void setEnderecoImpressora(String enderecoImpressora) {
		this.enderecoImpressora = enderecoImpressora;
	}

	public void setTexto(List<String> texto) {
		this.texto = texto;
	}

	public int getTipoImpressao() {
		return tipoImpressao;
	}

	public void setTipoImpressao(int tipoImpressao) {
		this.tipoImpressao = tipoImpressao;
	}
}
